package com.dragon.common.base.json;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 严格类型适配器工厂
 * 该工厂会严格校验 JSON 字符串中的字段是否与 Java 类的字段类型匹配，
 * 并支持嵌套对象的严格校验。
 * 当 strictNestedObjects 为 true 时，会校验嵌套对象的字段类型是否匹配。
 * 当 strictNestedObjects 为 false 时，会忽略嵌套对象的字段类型校验。
 */
public class StrictTypeAdapterFactory implements TypeAdapterFactory {
    private final boolean strictNestedObjects;

    public StrictTypeAdapterFactory(boolean strictNestedObjects) {
        this.strictNestedObjects = strictNestedObjects;
    }

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final Type actualType = type.getType();

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                JsonElement jsonElement = JsonParser.parseReader(in);
                if (!jsonElement.isJsonObject()) {
                    return delegate.fromJsonTree(jsonElement);
                }

                JsonObject jsonObject = jsonElement.getAsJsonObject();
                Map<String, Type> fieldTypes = getFieldTypes(actualType);

                // 检查外层字段名（忽略serialVersionUID）
                if (strictNestedObjects) {
                    for (String fieldName : fieldTypes.keySet()) {
                        if ("serialVersionUID".equals(fieldName)) {
                            continue;
                        }
                        Type fieldType = fieldTypes.get(fieldName);
                        // 基本类型不能为null
                        if (isPrimitiveType(fieldType) && !jsonObject.has(fieldName)) {
                            throw new JsonSyntaxException("Missing required primitive field: " + fieldName);
                        }
                    }
                }

                // 检查字段类型
                for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                    String jsonKey = entry.getKey();
                    JsonElement jsonValue = entry.getValue();

                    if (!fieldTypes.containsKey(jsonKey)) {
                        if (strictNestedObjects) {
                            throw new JsonSyntaxException("Unknown field '" + jsonKey + "' in JSON");
                        }
                        continue;
                    }

                    Type fieldType = fieldTypes.get(jsonKey);
                    if (!isTypeMatch(jsonValue, fieldType, gson, strictNestedObjects)) {
                        throw new JsonSyntaxException(
                            "Type mismatch for field '" + jsonKey + "': " +
                            "Expected " + getTypeName(fieldType) + ", " +
                            "but got " + getJsonValueType(jsonValue)
                        );
                    }
                }

                return delegate.fromJsonTree(jsonElement);
            }
        };
    }

    /** 检查 List 元素类型 */
    private boolean checkListItems(JsonElement jsonValue, Type elementType, Gson gson, boolean strict) {
        if (!jsonValue.isJsonArray()) {
            return false;
        }
        for (JsonElement item : jsonValue.getAsJsonArray()) {
            if (!isTypeMatch(item, elementType, gson, strict)) {
                return false;
            }
        }
        return true;
    }

    /** 检查 Map 值类型 */
    private boolean checkMapValues(JsonElement jsonValue, Type valueType, Gson gson, boolean strict) {
        if (!jsonValue.isJsonObject()) {
            return false;
        }
        for (JsonElement mapValue : jsonValue.getAsJsonObject().asMap().values()) {
            if (!isTypeMatch(mapValue, valueType, gson, strict)) {
                return false;
            }
        }
        return true;
    }

    /** 判断类型是否匹配（核心逻辑） */
    private boolean isTypeMatch(JsonElement jsonValue, Type targetType, Gson gson, boolean strict) {
        if (jsonValue.isJsonNull()) {
            return !isPrimitiveType(targetType);
        }

        // 处理泛型参数（如 T）
        if (targetType instanceof TypeVariable) {
            return true; // 跳过检查，由Gson处理转换
        }

        // 处理 Object 类型
        if (targetType == Object.class) {
            return true;
        }

        // 数字类型兼容性检查
        if (jsonValue.isJsonPrimitive() && jsonValue.getAsJsonPrimitive().isNumber()) {
            return isNumberTypeCompatible(targetType, jsonValue.getAsNumber());
        }

        // 处理数字类型兼容性
        if (jsonValue.isJsonPrimitive() && jsonValue.getAsJsonPrimitive().isNumber()) {
            return isNumberTypeCompatible(targetType, jsonValue.getAsNumber());
        }

        // 基本类型检查
        if (targetType == String.class) {
            return jsonValue.isJsonPrimitive() && jsonValue.getAsJsonPrimitive().isString();
        } else if (targetType == boolean.class || targetType == Boolean.class) {
            return jsonValue.isJsonPrimitive() && jsonValue.getAsJsonPrimitive().isBoolean();
        }

        // 处理 List
        if (isListType(targetType)) {
            return checkListItems(jsonValue, getGenericParameter(targetType), gson, strict);
        }

        // 处理 Map
        if (isMapType(targetType)) {
            return checkMapValues(jsonValue, getGenericParameter(targetType), gson, strict);
        }

        // 自定义对象：递归检查
        if (jsonValue.isJsonObject() && isCustomClass(targetType)) {
            try {
                if (strict) {
                    JsonObject nestedObj = jsonValue.getAsJsonObject();
                    Map<String, Type> nestedFieldTypes = getFieldTypes(targetType);
                    for (String fieldName : nestedFieldTypes.keySet()) {
                        if ("serialVersionUID".equals(fieldName)) {
                            continue;
                        }
                        Type nestedFieldType = nestedFieldTypes.get(fieldName);
                        // 基本类型不能为null
                        if (isPrimitiveType(nestedFieldType) && !nestedObj.has(fieldName)) {
                            return false;
                        }
                    }
                }
                gson.fromJson(jsonValue, targetType);
                return true;
            } catch (JsonSyntaxException e) {
                return false;
            }
        }

        return false;
    }

    /** 数字类型兼容性检查 */
    private boolean isNumberTypeCompatible(Type targetType, Number number) {
        if (targetType == int.class || targetType == Integer.class) {
            return number.intValue() == number.doubleValue(); // 检查是否为整数
        } else if (targetType == long.class || targetType == Long.class) {
            return number.longValue() == number.doubleValue();
        } else if (targetType == float.class || targetType == Float.class) {
            return true;
        } else if (targetType == double.class || targetType == Double.class) {
            return true;
        } else if (targetType == short.class || targetType == Short.class) {
            int value = number.intValue();
            return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE;
        } else if (targetType == byte.class || targetType == Byte.class) {
            int value = number.intValue();
            return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
        }
        return false;
    }

    /** 判断是否为基本类型 */
    private boolean isPrimitiveType(Type type) {
        if (type instanceof Class) {
            Class<?> clazz = (Class<?>) type;
            return clazz.isPrimitive();
        }
        return false;
    }

    /** 判断是否为 List 类型 */
    private boolean isListType(Type type) {
        if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            return List.class.isAssignableFrom((Class<?>) rawType);
        }
        return false;
    }

    /** 判断是否为 Map 类型 */
    private boolean isMapType(Type type) {
        if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            return Map.class.isAssignableFrom((Class<?>) rawType);
        }
        return false;
    }

    /** 获取泛型参数 */
    private Type getGenericParameter(Type type) {
        if (type instanceof ParameterizedType) {
            return ((ParameterizedType) type).getActualTypeArguments()[0];
        }
        return Object.class;
    }

    /** 判断是否为自定义类 */
    private boolean isCustomClass(Type type) {
        if (type instanceof Class) {
            Class<?> clazz = (Class<?>) type;
            return !clazz.isPrimitive() && 
                   !clazz.getName().startsWith("java.") && 
                   !clazz.getName().startsWith("javax.");
        }
        return false;
    }

    /** 获取类型名称（用于错误提示） */
    private String getTypeName(Type type) {
        if (type instanceof Class) {
            return ((Class<?>) type).getSimpleName();
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            StringBuilder sb = new StringBuilder();
            sb.append(((Class<?>) pType.getRawType()).getSimpleName());
            sb.append("<");
            Type[] args = pType.getActualTypeArguments();
            for (int i = 0; i < args.length; i++) {
                if (i > 0) sb.append(", ");
                sb.append(getTypeName(args[i]));
            }
            sb.append(">");
            return sb.toString();
        }
        return type.toString();
    }

    /** 获取 JSON 值的类型（用于错误提示） */
    private String getJsonValueType(JsonElement jsonValue) {
        if (jsonValue.isJsonNull()) return "null";
        if (jsonValue.isJsonPrimitive()) {
            JsonPrimitive primitive = jsonValue.getAsJsonPrimitive();
            if (primitive.isString()) return "String";
            if (primitive.isNumber()) return "Number";
            if (primitive.isBoolean()) return "Boolean";
        }
        if (jsonValue.isJsonArray()) return "Array";
        if (jsonValue.isJsonObject()) return "Object";
        return "Unknown";
    }

    /** 
     * 获取类的字段名及其类型（忽略serialVersionUID）
     * 修改：现在会递归获取所有父类的字段，包括继承的字段
     */
    private Map<String, Type> getFieldTypes(Type type) {
        Class<?> rawClass = type instanceof ParameterizedType 
            ? (Class<?>) ((ParameterizedType) type).getRawType() 
            : (Class<?>) type;
        
        Map<String, Type> fieldTypes = new HashMap<>();
        
        // 递归遍历类层次结构，获取所有字段（包括父类）
        Class<?> currentClass = rawClass;
        while (currentClass != null && currentClass != Object.class) {
            // 获取当前类的所有声明字段
            for (Field field : currentClass.getDeclaredFields()) {
                String fieldName = field.getName();
                // 忽略 serialVersionUID 字段
                if ("serialVersionUID".equals(fieldName)) {
                    continue;
                }
                // 如果字段名已存在（子类字段覆盖父类字段），跳过父类的同名字段
                if (!fieldTypes.containsKey(fieldName)) {
                    fieldTypes.put(fieldName, field.getGenericType());
                }
            }
            // 继续向上遍历父类
            currentClass = currentClass.getSuperclass();
        }
        
        return fieldTypes;
    }
}